﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using T.FAS.Runtime.Metadata.Entity;
using T.ServiceComponent.DAC.Service;
using T.ServiceComponent.DataAccessEx.Core;

namespace T.FAS.Runtime.Metadata.Dao
{
    /// <summary>
    /// 元数据依赖关系持久化类
    /// </summary>
    public class MetaDataDependencySlimDao : DaoService<MetaDataDependencySlim>
    {
        public MetaDataDependencySlimDao(string db = "TFAS") : base()
        {
            this.DBName = db;
        }

        public override string IDColumnName
        {
            get
            {
                return "ID";
            }
        }

        public override string TableName
        {
            get
            {
                return "Meta_Dependency";
            }
        }

        private List<string> exceptColumns = new List<string> { "ParentMetaDependMetaDatas" };
        public override List<string> ExceptColumnName => exceptColumns;


        public List<MetaDataDependencySlim> GetDependMetadatas(string metadataId, string projectBranchId, bool isContainPublic = false, MetaDataDependencyType dependType = MetaDataDependencyType.None)
        {
            var curUser = UserUtil.GetCurrentUserID();
            var dependMetadatas = new List<MetaDataDependencySlim>();
            List<IDbDataParameter> paramsList = new List<IDbDataParameter>();
            string sqlCondition = $@"
(info.ID=@MetaDataID Or info.Code=@MetaDataID) 
AND dep.ProjectBranchID = @ProjectBranchID
AND (dep.DeleteMark is null or dep.DeleteMark != 1)
AND parentInfo.Code is not null";
            if (DB.DbType == TDbType.MySql)
            {
                sqlCondition = string.Format("{0} AND ( ifnull( dep.checkoutuserid, '' )= '' OR dep.checkoutuserid = @CurrentUserID )", sqlCondition);
            }
            else if(DB.DbType == TDbType.PostgreSQL){
                sqlCondition = string.Format("{0} AND ( COALESCE( dep.checkoutuserid, '' )= '' OR dep.checkoutuserid = @CurrentUserID )", sqlCondition);
            }

            paramsList.Add(this.DB.MakeInParam("@MetaDataID", TDbDataType.VarChar, metadataId));
            paramsList.Add(this.DB.MakeInParam("@ProjectBranchID", TDbDataType.VarChar, projectBranchId));
            paramsList.Add(this.DB.MakeInParam("@CurrentUserID", TDbDataType.VarChar, curUser));
            if (dependType != MetaDataDependencyType.None) {
                sqlCondition = string.Format("{0} AND dep.DependencyType=@DependencyType", sqlCondition);
                paramsList.Add(this.DB.MakeInParam("@DependencyType", TDbDataType.Int, (int)dependType));
            }
            var sql = $@"
SELECT
	dep.ID,
	dep.MetaDataID,
	dep.ParentMetaDataID,
    dep.CheckOutUserID,
    info.MetaTypeID AS MetaDataType,
	type.CODE AS MetaDataTypeAbbr,
	parentInfo.CODE AS ParentMetaDataCode,
	parentInfo.MetaTypeID AS ParentMetaDataType,
	parentType.CODE AS ParentMetaDataTypeAbbr,
	parentInfo.LastModifyTime AS ParentMetaDataLastModifyTime 
FROM
	meta_dependency dep
	LEFT JOIN meta_basicinfo info ON dep.MetaDataID = info.id AND dep.ProjectBranchID = info.ProjectBranchID AND info.MetadataStatus != 5
	LEFT JOIN meta_typeinfo type ON info.MetaTypeID = type.ID 
	LEFT JOIN meta_basicinfo parentInfo ON dep.ParentMetaDataID = parentInfo.id AND (dep.ProjectBranchID = parentInfo.ProjectBranchID {(isContainPublic ? "or parentInfo.ProjectBranchID='Public'" : "")}) AND parentInfo.MetadataStatus != 5
	LEFT JOIN meta_typeinfo parentType ON parentInfo.MetaTypeID = parentType.ID 
WHERE
	{sqlCondition}
"; 
            var ds = DB.ExecuteDataSet(sql, paramsList.ToArray());

            dependMetadatas = DaoUtil.ConvertToEntity<MetaDataDependencySlim>(ds?.Tables[0], this.ExceptColumnName);

            var parentMetaDependMetas = GetDependMetadataDepenMetas(metadataId, projectBranchId, isContainPublic, dependType);
            if (parentMetaDependMetas != null)
            {
                foreach (var meta in dependMetadatas)
                {
                    meta.ParentMetaDependMetaDatas = parentMetaDependMetas.Where(parDen => parDen.MetadataID == meta.ParentMetadataID)?.ToList();
                }
            }
            return dependMetadatas;
        }

        public List<MetaDataDependencySlim> GetDependMetadataDepenMetas(string metadataId, string projectBranchId, bool isContainPublic, MetaDataDependencyType dependType = MetaDataDependencyType.None)
        {
            var curUser = UserUtil.GetCurrentUserID();
            var dependMetadatas = new List<MetaDataDependencySlim>();
            List<IDbDataParameter> paramsList = new List<IDbDataParameter>();
            //只过滤父级为CDO、Action的情况
            string ifnull = "ifnull";
            if (DB.DbType == TDbType.PostgreSQL)
            {
                ifnull = "COALESCE";
            }
                string sqlCondition = $@"
(dep.DeleteMark is null or dep.DeleteMark != 1) 
AND dep.ProjectBranchID = @ProjectBranchID 
AND ( {ifnull}( dep.checkoutuserid, '' )= '' OR dep.checkoutuserid = @CurrentUserID )
AND info.ID in (
    SELECT
		parentInfo.ID
	FROM
		meta_dependency dep
		LEFT JOIN meta_basicinfo info ON dep.MetaDataID = info.id AND dep.ProjectBranchID = info.ProjectBranchID AND info.MetadataStatus != 5
		LEFT JOIN meta_basicinfo parentInfo ON dep.ParentMetaDataID = parentInfo.id AND (dep.ProjectBranchID = parentInfo.ProjectBranchID {(isContainPublic ? "or parentInfo.ProjectBranchID='Public'" : "")}) AND parentInfo.MetadataStatus != 5
		LEFT JOIN meta_typeinfo parentType ON parentInfo.MetaTypeID = parentType.ID 
	WHERE
		(info.ID = @MetaDataID or info.Code = @MetaDataID) 
		AND dep.ProjectBranchID = @ProjectBranchID 
		AND ( dep.DeleteMark IS NULL OR dep.DeleteMark != 1 ) 
        AND parentInfo.Code is not null
		AND (ifnull(dep.checkoutuserid, '' )='' OR dep.checkoutuserid = @CurrentUserID )
		AND parentInfo.ID != '' 
        AND parentInfo.id is not NULL
		AND	parentType.Code in ('CDO', 'Action')
);";
            paramsList.Add(this.DB.MakeInParam("@MetaDataID", TDbDataType.VarChar, metadataId));
            paramsList.Add(this.DB.MakeInParam("@ProjectBranchID", TDbDataType.VarChar, projectBranchId));
            paramsList.Add(this.DB.MakeInParam("@CurrentUserID", TDbDataType.VarChar, curUser));
            if (dependType != MetaDataDependencyType.None)
            {
                sqlCondition = string.Format("{0} AND dep.DependencyType=@DependencyType", sqlCondition);
                paramsList.Add(this.DB.MakeInParam("@DependencyType", TDbDataType.Int, (int)dependType));
            }
            var sql = $@"
SELECT
	dep.ID,
	dep.MetaDataID,
	dep.ParentMetaDataID,
    dep.CheckOutUserID,
    info.MetaTypeID AS MetaDataType,
	type.CODE AS MetaDataTypeAbbr,
	parentType.CODE AS ParentMetaDataTypeAbbr,
	parentInfo.CODE AS ParentMetaDataCode,
	parentInfo.MetaTypeID AS ParentMetaDataType,
	parentInfo.LastModifyTime AS ParentMetaDataLastModifyTime 
FROM
	meta_dependency dep
	LEFT JOIN meta_basicinfo info ON dep.MetaDataID = info.id AND dep.ProjectBranchID = info.ProjectBranchID AND info.MetadataStatus != 5
	LEFT JOIN meta_typeinfo type ON info.MetaTypeID = type.ID 
	LEFT JOIN meta_basicinfo parentInfo ON dep.ParentMetaDataID = parentInfo.id AND (dep.ProjectBranchID = parentInfo.ProjectBranchID {(isContainPublic ? "or parentInfo.ProjectBranchID='Public'" : "")}) AND parentInfo.MetadataStatus != 5
	LEFT JOIN meta_typeinfo parentType ON parentInfo.MetaTypeID = parentType.ID 
WHERE
	{sqlCondition}
";
            var ds = DB.ExecuteDataSet(sql, paramsList.ToArray());
            dependMetadatas = DaoUtil.ConvertToEntity<MetaDataDependencySlim>(ds?.Tables[0], this.ExceptColumnName);

            return dependMetadatas;
        }
    }
}
